package dao.implementations;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
//import java.util.Locale;


import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import dao.interfaces.IBase;
import dao.interfaces.IDAOFacade;
import dao.interfaces.ILogFacade;
import utils.SessionUtils;

/**
 * <desc>DaoJpaHibernate implement the interface DaoOperationFacade</desc>
 * <responsibility>Implement the operations of database for framework JPA -
 * Hibernate</responsibility> <coperation>All classes that need to work with
 * database</coperation>
 * 
 * @version 0.2 Create 18-03-2009 Author Alfred Oliver
 * 
 *          Updated 07-05-2013 Revision Eduard Escrihuela
 */
@SuppressWarnings("serial")
public class DAOJPAHibernate implements IDAOFacade, Serializable {
	/** Singleton. */
	private static DAOJPAHibernate DAOManager = null;

	/**
	 * Field that contain the interface used to interact with the persistence
	 * context.
	 */
	private EntityManager em;

	/** Field that contain the result to operation */
	private boolean operationResult;

	/** Field that contain the log to record the operations performed */
	private ILogFacade log;

	private String setUserAndDate(IBase objt) {
		String user = (String) SessionUtils.getSessionAttribute("user");
		if (user == null)
			user = "Unknown";
		objt.setDate(new Date());
		objt.setUser(user);
		return user;
	}

	/**
	 * PRIVATE Constructor of class DaoJpaHibernate.-->Singleton
	 * 
	 * @throws DataException.
	 * @param PUser
	 *            . Registered User.
	 * @param pDataBase
	 *            . Attribute name of node persistence-unit (file
	 *            persistence.xml)
	 * @param pLog
	 *            . To record the operations performed.
	 */
	private DAOJPAHibernate(String entityManagerName, ILogFacade log) {
		this.log = log;
		JPAconnect(entityManagerName);
	}

	/**
	 * Procedure that connects to database {Pre: There isn't an open connection
	 * to the database}. {Post: has connect to database}.
	 * 
	 * @throws DataException
	 *             if there isn't a connection to the database.
	 * @param pDataBase
	 *            . Attribute name of node persistence-unit (file
	 *            persistence.xml)
	 */
	private void JPAconnect(String entityManagerName) {
		EntityManagerFactory factory;
		try {

			// factory =
			// Persistence.createEntityManagerFactory(entityManagerName,
			// System.getProperties());
			factory = Persistence.createEntityManagerFactory(entityManagerName);
			em = factory.createEntityManager();

		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * Get SINGLETON object
	 */

	public static DAOJPAHibernate getDAOManager(String DAOMangerName,
			ILogFacade log) {
		if (DAOManager == null) {
			DAOManager = new DAOJPAHibernate(DAOMangerName, log);
		}
		return DAOManager;
	}

	@Override
	public void beginTrans() {
		EntityTransaction tx = em.getTransaction();
		tx.begin();
	}

	@Override
	public void commitTrans() {
		EntityTransaction tx = em.getTransaction();
		tx.commit();
	}

	@Override
	public void rollbackTrans() {
		EntityTransaction tx = em.getTransaction();
		tx.rollback();
	}

	@Override
	public boolean isOperationResult() {
		return operationResult;
	}

	/**
	 * Persist object. {Pre: The object no exist}. {Post: The object is persist
	 * is not exist.
	 */
	@Override
	public void insert(IBase obj) {

		operationResult = false;

		try {
			// String user=setUserAndDate(obj);
			// Locale locale=SessionUtils.getSessionLocale();
			setUserAndDate(obj);
			beginTrans();
			em.persist(obj);
			commitTrans();
			operationResult = true;
			/*
			 * log.saveLog( new LogLine( MessageUtils.getMessage("messageLog",
			 * "new_OK",locale ) + obj.getClass().getCanonicalName() +
			 * " id="+obj.getId(), " ",user));
			 */
		} catch (Exception ex) {
			operationResult = false;
			ex.printStackTrace();
		}

	}

	/**
	 * Update object. {Pre: The object exist}. {Post: The object is update if
	 * exist.
	 */
	@Override
	public void update(IBase obj) {

		operationResult = false;

		try {
			// String user=setUserAndDate(obj);
			// Locale locale=SessionUtils.getSessionLocale();
			setUserAndDate(obj);
			beginTrans();
			em.merge(obj);
			commitTrans();
		} catch (Exception ex) {
			operationResult = false;
			ex.printStackTrace();
		}
	}

	/**
	 * Remove object. {Pre: The object exist}. {Post: The object is remove.
	 */
	@Override
	public void delete(IBase obj) {

		operationResult = false;

		try {
			beginTrans();
			em.remove(obj);
			commitTrans();
		} catch (Exception ex) {
			ex.printStackTrace();
			operationResult = false;
		}
	}

	/**
	 * Find object of type IBase by primary key. {Pre: Primary key of object}.
	 * {Post: return object if exist}.
	 */
	@Override
	public IBase findObjectByPK(Class<? extends IBase> entityClass, long id) {

		operationResult = false;
		IBase new_obj = null;
		try {
			new_obj = em.find(entityClass, id);
			operationResult = true;
		} catch (Exception ex) {
			ex.printStackTrace();
			operationResult = true;
			return null;
		}
		return new_obj;
	}

	/**
	 * Find object by field unique description. {Pre: Field description}. {Post:
	 * return object if exist}.
	 */
	@Override
	public IBase findObjectByDescription(Class<? extends IBase> entityClass,
			String description) {

		operationResult = false;
		List<? extends IBase> objLst = null;
		IBase new_IBase = null;

		try {
			objLst = (List<? extends IBase>) em
					.createQuery(
							"select o from "
									+ entityClass.getSimpleName()
									+ " o where o.description like :pDescription")
					.setParameter("pDescription", description).getResultList();

			if (objLst.size() == 1) {

				new_IBase = objLst.get(0);
				operationResult = true;
			}
		} catch (Exception ex) {
			operationResult = false;
			return null;
		}
		return new_IBase;

	}

	/**
	 * Find objects by some criterion. {Pre: Some criterion}. {Post: return List
	 * objects if exist}.
	 * 
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	@Override
	public List<? extends IBase> getObjectList(
			Class<? extends IBase> entityClass, String criteria) {

		List<? extends IBase> objLst = null;
		operationResult = false;
		String className = entityClass.getSimpleName();
		String dbCriteria = "select " + className + " from " + className + " "
				+ className + " " + criteria;

		try {
			// System.out.println(dbCriteria);
			objLst = (List<? extends IBase>) em.createQuery(dbCriteria)
					.getResultList();

		} catch (Exception ex) {

			ex.printStackTrace();
		}

		if (objLst.size() > 0)
			operationResult = true;

		return objLst;
	}

	/** Instance associated with a persistence context */

	public EntityManager getEntityManager() {
		return em;
	}

	public static void main(String[] args) {

	}

	@Override
	public void enableLog(Boolean enabled) {
		log.enableLog(enabled);
	}

}
